package org.baicaixiaozhan.namingformat.action;

import com.google.common.base.CaseFormat;
import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.actionSystem.LangDataKeys;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.editor.Caret;
import com.intellij.openapi.editor.CaretModel;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.ui.popup.JBPopup;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.psi.PsiElement;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * DESC: 命名格式化
 *
 * @author : baicaixiaozhan
 * @since : 2021-03-20
 */
public class NamingFormatAction extends AnAction {

    @Override
    public void update(AnActionEvent event) {
        event.getPresentation().setEnabledAndVisible(hasSelection(event));
    }

    @Override
    public void actionPerformed(AnActionEvent event) {
        Set<String> set = Sets.newHashSet();
        String finalValue = getFinalSelectedValue(event);

        setFinalValues(set, finalValue);
        List<String> finalList = set.stream().filter(value -> !finalValue.equals(value))
                .collect(Collectors.toList());

        JBPopup listPopup = JBPopupFactory.getInstance()
                .createPopupChooserBuilder(finalList)
                .setItemChosenCallback(item -> replaceSelectedValue(event, item, finalValue))
                .createPopup();
        listPopup.showInBestPositionFor(event.getRequiredData(CommonDataKeys.EDITOR));
    }

    private void replaceSelectedValue(AnActionEvent event, String item, String finalValue) {
        Editor editor = event.getRequiredData(CommonDataKeys.EDITOR);
        Document document = editor.getDocument();
        // CommandProcessor , 避免 Must not change document outside command or undo-transparent action 报错
        CommandProcessor.getInstance().executeCommand(event.getProject(),
                () -> {
                    Caret currentCaret = editor.getCaretModel().getCurrentCaret();
                    if (currentCaret.hasSelection()) {
                        int selectionStart = currentCaret.getSelectionStart();
                        int selectionEnd = currentCaret.getSelectionEnd();
                        insertValueInPsiFile(item, document, currentCaret, selectionStart, selectionEnd);
                        return;
                    }

                    PsiElement element = event.getData(LangDataKeys.PSI_ELEMENT);
                    if (!Strings.isNullOrEmpty(element.toString())) {
                        int startOffset = element.getTextOffset();
                        int endOffset = startOffset + finalValue.length();
                        insertValueInPsiFile(item, document, currentCaret, startOffset, endOffset);
                    }
                },
                "",
                null,
                document);
    }

    private void insertValueInPsiFile(String item, Document document, Caret currentCaret,
                                      int selectionStart, int selectionEnd) {
        document.deleteString(selectionStart, selectionEnd);
        document.insertString(selectionStart, item);
        currentCaret.setSelection(selectionStart, selectionStart + item.length());
    }

    /**
     * 设置 最终显示的选项值
     *
     * @param set
     * @param finalValue
     */
    static void setFinalValues(Set<String> set, String finalValue) {
        Arrays.stream(CaseFormat.values()).forEach(caseFormat -> {
            set.add(CaseFormat.LOWER_CAMEL.to(caseFormat, finalValue));
            set.add(CaseFormat.LOWER_HYPHEN.to(caseFormat, finalValue));
            set.add(CaseFormat.LOWER_UNDERSCORE.to(caseFormat, finalValue));
            set.add(CaseFormat.UPPER_UNDERSCORE.to(caseFormat, finalValue));
            set.add(CaseFormat.UPPER_CAMEL.to(caseFormat, finalValue));
        });
    }


    private Boolean hasSelection(AnActionEvent event) {
        Editor editor = event.getRequiredData(CommonDataKeys.EDITOR);
        CaretModel caretModel = editor.getCaretModel();
        boolean hasSelection = caretModel.getCurrentCaret().hasSelection();
        PsiElement element = event.getData(LangDataKeys.PSI_ELEMENT);
        if (Objects.nonNull(element)) {
            return hasSelection || !Strings.isNullOrEmpty(element.toString());
        }
        return hasSelection;
    }

    /**
     * 获取最终选中的字符串 (命名)
     *
     * @param event
     * @throws IllegalStateException
     * @return selectedText
     */
    private String getFinalSelectedValue(AnActionEvent event) {
        String selectedText = event.getData(LangDataKeys.EDITOR)
                .getCaretModel().getCurrentCaret().getSelectedText();
        if (!Strings.isNullOrEmpty(selectedText)) {
            return selectedText;
        }
        String psiElement = event.getData(LangDataKeys.PSI_ELEMENT).toString();
        if (!Strings.isNullOrEmpty(psiElement)) {
            return psiElement.substring(psiElement.indexOf(":") + 1);
        }
        throw new IllegalStateException();
    }
}
